package com.github.kezhenxu94.acs;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import com.github.kezhenxu94.acs.common.Agent;
import com.github.kezhenxu94.acs.common.Environment;
import com.github.kezhenxu94.acs.common.Model;
import com.github.kezhenxu94.acs.math.Maths;
import com.github.kezhenxu94.acs.math.Matrix;

/**
 * Created by kezhenxu on Dec 19, 2016
 *
 * @author kezhenxu (kezhenxu94@163.com)
 */
public class Ant implements Agent {
	private static final Logger logger = Logger.getLogger(Ant.class.getName());

	protected Environment environment;

	@Override
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}

	@Override
	public Environment getEnvironment() {
		return environment;
	}

	@Override
	public Model construct() {
		Solution solution = new Solution(environment.getRowCount());
		int N = environment.getRowCount();

		Matrix q0Matrix = new Matrix(1, N, environment.getEvaporationRate());
		Matrix randMat = Matrix.random(1, N);
		Matrix differ = randMat.minus(q0Matrix);
		List<Integer> procedure1 = new ArrayList<>();
		List<Integer> procedure2 = new ArrayList<>();
		for (int i = 0; i < N; i++) {
			if (differ.get(0, i) <= 0) {
				procedure1.add(i);
			} else {
				procedure2.add(i);
			}
		}
		logger.info("Procedure I indices: " + procedure1 + ", procedure II indices: " + procedure2);
		Matrix pheromone = environment.getPheromone();
		// perform procedure I
		for (int i : procedure1) {
			double maxPheromone = Double.NEGATIVE_INFINITY;
			for (int col = 0; col < pheromone.getColumnCount(); col++) {
				if (pheromone.get(i, col) > maxPheromone) {
					solution.assignCluster(i, col);
				}
			}
		}
		// perform procedure II
		for (int i : procedure2) {
			double[] wheel = Maths.cumsum(pheromone.getArray()[i]);
			double rand = environment.getRandomGenerator().nextDouble();
			for (int j = 0; j < wheel.length; j++) {
				if (wheel[j] - rand <= 0) {
					solution.assignCluster(i, j);
					break;
				}
				wheel[j] -= rand;
			}
		}
		return solution;
	}

}
